package com.xiaodeng.xdblogspringboot.service.impl;

import cn.hutool.core.lang.UUID;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.xiaodeng.xdblogspringboot.exception.ArticleException;
import com.xiaodeng.xdblogspringboot.mapper.ApplicationMapper;
import com.xiaodeng.xdblogspringboot.mapper.ArticleMapper;
import com.xiaodeng.xdblogspringboot.pojo.Application;
import com.xiaodeng.xdblogspringboot.pojo.Article;
import com.xiaodeng.xdblogspringboot.pojo.PageBean;
import com.xiaodeng.xdblogspringboot.pojo.Result;
import com.xiaodeng.xdblogspringboot.service.ArticleService;
import com.xiaodeng.xdblogspringboot.utils.RedisLockUtil;
import com.xiaodeng.xdblogspringboot.utils.ThreadLocalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

import static com.xiaodeng.xdblogspringboot.constant.RedisConstants.ARTICLE_LOCK_KEY;
import static com.xiaodeng.xdblogspringboot.constant.RedisConstants.VIEW_COUNT_KEY;

@Service
public class ArticleServiceImpl implements ArticleService {
    @Autowired
    private ArticleMapper articleMapper;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private ApplicationMapper applicationMapper;
    @Autowired
    private RedisLockUtil redisLock;

    /**
     * 分页查询文章列表功能
     *
     */
    @Override
    public PageBean<Article> articlelist(Integer pageNum, Integer pageSize, String title, List<String> categoryName) {
        //创建pageBean对象
        PageBean<Article> pb = new PageBean<>();
        //开启分页查询
        PageHelper.startPage(pageNum,pageSize);
        //调用mapper
        Integer categoryNameSize = categoryName != null ? categoryName.size() : 0;
        List<Article> as = articleMapper.articlelist(title,categoryName,categoryNameSize);
        Page<Article> p =(Page<Article>) as;
        //把数据填充到pageBean
        //获取总条数
        pb.setTotal(p.getTotal());
        //获取当前页的数据
        pb.setItems(p.getResult());
        return pb;
    }

    //  获取文章列表
    @Override
    public PageBean<Article> articleList(Integer pageNum, Integer pageSize, String title, List<String>  categoryName) {
        //创建pageBean对象
        PageBean<Article> pb = new PageBean<>();
        //开启分页查询
        PageHelper.startPage(pageNum,pageSize);
        //调用mapper
        Integer categoryNameSize = categoryName != null ? categoryName.size() : 0;
        List<Article> as = articleMapper.articleList(title,categoryName,categoryNameSize);
        Page<Article> p =(Page<Article>) as;
        //把数据填充到pageBean
        //获取总条数
        pb.setTotal(p.getTotal());
        //获取当前页的数据
        pb.setItems(p.getResult());
        return pb;
    }

    //新增文章
    @Transactional
    @Override
    public void addarticle(Article article, List<String> categoryId) {
        Map<String, Object> map = ThreadLocalUtil.get();
        Integer createId = (Integer) map.get("id");
        String lockKey = ARTICLE_LOCK_KEY + createId; // 根据 用户ID 生成锁的 key
        String lockValue = UUID.randomUUID().toString(); // 生成唯一的锁标识(后续换成文章标题图像为唯一标识)

        // 尝试获取分布式锁
        boolean unlock = redisLock.tryLock(lockKey, lockValue, 10);
        if (!unlock) {
            System.out.println("获取锁失败，用户ID: " + lockKey);
            throw new ArticleException(400, "您操作的太快了，请勿重复提交");
        }
        try {
            // 执行新增文章的操作
            article.setViewCount(0);
            article.setCreateTime(LocalDateTime.now());
            article.setUpdateTime(LocalDateTime.now());
            articleMapper.addarticle(article, createId);

            // 确保在插入后获取 ID
            Integer articleId = article.getId();
            if (articleId == null) {
                throw new ArticleException(402, "新增文章失败，文章 ID 为 null");
            }

            // 向文章类型表里面选择一个类型Id（由前端传过来）
            if (categoryId == null || categoryId.isEmpty()) {
                throw new ArticleException(402, "文章类型 ID 不能为空");
            }

            // 将文章id和类型Id插入到关联表中
            articleMapper.acRelation(articleId, categoryId);

            // 创建申请记录
            Application application = new Application();
            application.setArticleId(articleId);
            application.setApplicantId(createId); // 使用创建者的 ID
            application.setAuditStatus("待审核"); // 默认状态为待审核
            application.setApplicationTime(LocalDateTime.now()); // 当前时间

            // 插入申请记录到数据库
            applicationMapper.application(application);
        } catch (Exception e) {
            // 可选择记录日志
            throw new ArticleException(500, "新增文章过程中发生错误: " + e.getMessage());
        }
    }


    //根据文章Id查询文章
    @Override
    public Article getarticle(Integer articleId) {
        return articleMapper.getarticle(articleId);
    }

    //根据文章ID删除文章
    @Override
    @Transactional
    public void delArticle(Integer articleId) {
        Map<String,Object> map = ThreadLocalUtil.get();
        Integer userId = (Integer) map.get("id");
        // 删除文章类别关联表
        articleMapper.delACRelation(articleId);
        int deletedRows = articleMapper.delArticle(articleId,userId);
        // 检查删除结果
        if (deletedRows == 0) {
            throw new ArticleException(501,"未找到可删除的文章，或用户没有权限删除此文章");
        }
    }

    @Override
    public Integer getViewCount(Long articleId) {
        return articleMapper.getViewCount(articleId);
    }

    @Override
    public List<Article> getHotArticles(int limit) {
        return articleMapper.getHotArticles(limit);
    }

    @Override
    public Long incrementViewCount(Long articleId) {
        String key = VIEW_COUNT_KEY + articleId;
        // 检查 articleId 是否为 null
        if (articleId == null) {
            throw new ArticleException(500,"请输入文章ID");
        }
        ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
        // 检查 Redis 中是否存在该文章的浏览量
        if (Boolean.FALSE.equals(stringRedisTemplate.hasKey(key))){
            // 如果没有，先从数据库中获取初始值
            Integer count = this.getViewCount(articleId);
            if (count == null) {
                // 如果数据库中也没有，文章不存在，抛出异常
                throw new ArticleException(404, "文章不存在");
            }
            stringRedisTemplate.opsForValue().set(key, String.valueOf(count));
        }
        // 文章存在，增加浏览量
        Long increment = operations.increment(key, 1);
        this.updateViewCount(articleId);
        return Result.success(increment).getData();
    }

    //异步更新浏览量到数据库
    @Async
    public void updateViewCount(Long articleId) {
        // 从 Redis 获取浏览量
        String key = VIEW_COUNT_KEY + articleId;
        String countStr = stringRedisTemplate.opsForValue().get(key);
        Integer count = Integer.parseInt(countStr);

        // 更新数据库
        articleMapper.updateViewCount(articleId, count);
    }
    @Override
    @Transactional
    public void editArticle(Article article, List<String> categoryId) {
        Map<String, Object> map = ThreadLocalUtil.get();
        Integer userId = (Integer) map.get("id");

        article.setUpdateTime(LocalDateTime.now());
        int updatedRows = articleMapper.updateArticle(article, userId);
        if (updatedRows == 0) {
            throw new ArticleException(501, "未找到可编辑的文章，或用户没有权限编辑此文章");
        }
        // 删除原有的文章与类别关联关系
        articleMapper.deleteArticleCategoryRelation(article.getId());

        // 插入新的文章与类别关联关系
        if (categoryId != null && !categoryId.isEmpty()) {
            articleMapper.acRelation(article.getId(), categoryId);
        }
    }
}
